﻿using System;
using System.Data;
using Finance.Data;

namespace Finance
{
	public interface IDataBaseObjectCollection
	{
		void Save(object item);
	}

	public abstract class DataBaseObjectCollection : IDataBaseObjectCollection
	{
		public DataBase DataBase { get; private set; }
		public string TableName { get; private set; }

		protected DataBaseObjectCollection(DataBase dataBase, string tableName)
		{
			DataBase = dataBase;
			TableName = tableName;
		}

		public abstract void Save(object item);
	}

	public interface IDataBaseObjectCollection<T> where T: IDataBaseObject
	{
		T NewItem();
		void Delete(T item);
		void Save(T item);
		T GetItem(Guid guid);
	}

	public abstract class DataBaseObjectCollection<T> :
		 DataBaseObjectCollection, IDataBaseObjectCollection<T> where T : IDataBaseObject
	{
		private readonly string _tableName;
		protected string RemoveQuery;

		private string _idColumnName;

		public string IdColumn
		{
			set
			{
				_idColumnName = value;
				UpdateRemoveQuery();
			}
			get { return _idColumnName; }
		}
        
		protected DataBaseObjectCollection(DataBase dataBase, string tableName) : 
			base(dataBase, tableName)
		{
			_tableName = tableName;
			_idColumnName = tableName + "id";

			UpdateRemoveQuery();
		}

		private void UpdateRemoveQuery()
		{
			RemoveQuery = "delete from [" + _tableName + "] where [" + _idColumnName + "] = ?";
		}

		public override void Save(object item)
		{
			Save((T)item);
		}

		public void Save(T item)
		{
			if (item.Id == Guid.Empty)
			{
				Insert(item);
			}
			else
			{
				Update(item);
			}
		}

		public virtual T GetItem(Guid guid)
		{
			using (var reader = DataBase.Sql.ExecuteReader("select * from " + TableName))
			{
				return ParseItem(reader);
			}
		}

		protected abstract T ParseItem(IDataRecord reader);
		protected abstract void Update(T item);
		protected abstract void Insert(T item);

		public abstract T NewItem();

		public void Delete(T item)
		{
			using (var sql = ((FinanceDataBase) DataBase).OpenCommandProcessor())
			{
				sql.TransactionBegin();
				sql.ExecuteNonQuery(RemoveQuery, item.Id);
				sql.TransactionCommit();
			}
		}

		protected Guid GetGuid(IDataRecord dataRecord, string fieldName)
		{
			object obj = dataRecord[fieldName];
			return obj == DBNull.Value ? Guid.Empty : (Guid)obj;
		}

		protected string GetString(IDataRecord dataRecord, string fieldName)
		{
			object obj = dataRecord[fieldName];
			if (obj == DBNull.Value)
				return null;
			return (string)obj;
		}
	}
}
